#include "LumineSwapchain.hpp"
#include "Core/Texture/DepthTexture.hpp"
#include "Core/Texture/TextureManager.hpp"

namespace Lumine
{
    void LumineSwapchain::createSwapchain(GLFWwindow *window)
    {
        auto surfaceCapabilities = LumineContext::Get().PhysicalDevice().getSurfaceCapabilitiesKHR(LumineContext::Get().Surface());
        // 获取SurfaceFormat
        std::vector<vk::SurfaceFormatKHR> availableFormats = LumineContext::Get().PhysicalDevice().getSurfaceFormatsKHR(LumineContext::Get().Surface());
        vk::SurfaceFormatKHR tempFormat;
        for (const auto &item : availableFormats)
        {
            if (item.format == vk::Format::eB8G8R8A8Srgb && item.colorSpace == vk::ColorSpaceKHR::eSrgbNonlinear)
            {
                tempFormat = item;
                m_swapchainImageFormat = tempFormat.format;
            }
        }
        // 获取PresentMode
        std::vector<vk::PresentModeKHR> availablePresentModes = LumineContext::Get().PhysicalDevice().getSurfacePresentModesKHR(LumineContext::Get().Surface());
        vk::PresentModeKHR tempPresentMode = vk::PresentModeKHR::eFifo;
        for (const auto &item : availablePresentModes)
        {
            if (item == vk::PresentModeKHR::eMailbox)
            {
                tempPresentMode = item;
            }
        }
        // 获取SwapExtent
        vk::Extent2D tempExtent;
        if (surfaceCapabilities.currentExtent.width != std::numeric_limits<uint32_t>::max())
        {
            m_swapchainExtent = surfaceCapabilities.currentExtent;
        }
        int tempWidth, tempHeight;
        glfwGetFramebufferSize(window, &tempWidth, &tempHeight);
        tempExtent.width = std::clamp<uint32_t>(tempWidth, surfaceCapabilities.minImageExtent.width, surfaceCapabilities.maxImageExtent.width);
        tempExtent.height = std::clamp<uint32_t>(tempHeight, surfaceCapabilities.minImageExtent.height, surfaceCapabilities.maxImageExtent.height);

        // 获取ImageCount
        uint32_t imageCount = surfaceCapabilities.minImageCount + 1;
        // 设置CreateInfo
        vk::SwapchainCreateInfoKHR info;
        info.setFlags(vk::SwapchainCreateFlagBitsKHR())
            .setSurface(LumineContext::Get().Surface())
            .setMinImageCount(imageCount)
            .setImageFormat(tempFormat.format)
            .setImageColorSpace(tempFormat.colorSpace)
            .setImageExtent(m_swapchainExtent)
            .setImageArrayLayers(1)
            .setImageUsage(vk::ImageUsageFlagBits::eColorAttachment)
            .setImageSharingMode(vk::SharingMode::eExclusive)
            .setPreTransform(surfaceCapabilities.currentTransform)
            .setCompositeAlpha(vk::CompositeAlphaFlagBitsKHR::eOpaque)
            .setPresentMode(tempPresentMode)
            .setClipped(true)
            .setOldSwapchain(nullptr);
        createInfo = info;
        m_swapchain = vk::raii::SwapchainKHR(LumineContext::Get().Device(), info);
        m_swapchainImages = m_swapchain.getImages();
    }

    void LumineSwapchain::createImageViews()
    {
        m_swapchainImageViews.clear();
        vk::ImageViewCreateInfo info({}, {}, vk::ImageViewType::e2D, m_swapchainImageFormat, {}, {vk::ImageAspectFlagBits::eColor, 0, 1, 0, 1});
        for (auto image : m_swapchainImages)
        {
            info.image = image;
            m_swapchainImageViews.emplace_back(LumineContext::Get().Device(), info);
        }
    }

    void LumineSwapchain::Initialize(GLFWwindow *window, vk::SwapchainKHR old)
    {
        m_window = window;
        createSwapchain(window);
        createImageViews();
    }

    void LumineSwapchain::cleanup()
    {
        m_swapchainImageViews.clear();
        m_swapchain = nullptr;
    }

    void LumineSwapchain::recreate(GLFWwindow *window)
    {
        // 1. 处理最小化窗口（等待有效尺寸）
        int width = 0, height = 0;
        glfwGetFramebufferSize(window, &width, &height);
        while (width == 0 || height == 0)
        {
            glfwGetFramebufferSize(window, &width, &height);
            glfwWaitEvents();
        }
        LumineContext::Get().Device().waitIdle();
        vk::SwapchainKHR old = GetHandle();
        cleanup();
        TextureManager::depth.clear();
        Initialize(window, old);
    }
}